#lang racket


(require "../base/main.rkt")

(provide try-exn-connection
         try-void-connection
         
         list<vector<real>><-list<coord>
         list<coord><-vector<vector<real>>
         
         real<-number
         vector<real><-coord

         scale-matrix<-coord
         vector<vector<real>><-matrix
         
         vector<real><-list<number>

         flat-vector<real><-list<coord>
         list<coord><-flat-vector<number>
         list<coord><-flat-vector<number>-z
         
         flat-vector<real><-bbox)


; edit: worst possible hack; change MysterX exceptions
(define exn-re (regexp "code = 80010001"))

(define (try-exn-connection msg fn (count 5))
  (define (try-connection-handler e)
    (cond ((and (regexp-match exn-re (exn-message e)) (> count 0))
           (displayln msg)
           (sleep 1)
           (try-exn-connection msg fn (- count 1)))
          (else
           (raise e))))
  (with-handlers ((exn:fail? try-connection-handler))
    (fn)))

(define (try-void-connection msg fn (count 3))
  (let ((result (fn)))
    (if (void? result)
        (cond ((> count 0)
               (sleep 1)
               (try-void-connection msg fn (- count 1)))
              (else
               (error 'try-void-connection msg)))
        result)))

(define (list<vector<real>><-list<coord> ps)
  (map vector<real><-coord ps))

(define (list<coord><-vector<vector<real>> v)
  (map coord-of-vector (vector->list v)))

(define real<-number exact->inexact)

(define (vector<real><-coord c)
  (let ((x (real<-number (xyz-x c)))
        (y (real<-number (xyz-y c)))
        (z (real<-number (xyz-z c))))
    (vector x y z)))

(define (scale-matrix<-coord p)
  (let ((x (real<-number (xyz-x p)))
        (y (real<-number (xyz-y p)))
        (z (real<-number (xyz-z p))))
    (vector
     (vector  x  0.0 0.0 0.0)
     (vector 0.0  y  0.0 0.0)
     (vector 0.0 0.0  z  0.0)
     (vector 0.0 0.0 0.0 1.0))))

(define (vector<vector<real>><-matrix m)
  (vector
   (vector-map! real<-number (m-line m 0))
   (vector-map! real<-number (m-line m 1))
   (vector-map! real<-number (m-line m 2))
   (vector-map! real<-number (m-line m 3))))

(define (vector<real><-list<number> l)
  (list->vector (map real<-number l)))

(define (flat-vector<real><-list<coord> cs)
  (let ((v (make-vector (* (length cs) 3)))
        (i 0))
    (for ((c cs))
      (let ((x (real<-number (xyz-x c)))
            (y (real<-number (xyz-y c)))
            (z (real<-number (xyz-z c))))
        (vector-set! v (+ i 0) x)
        (vector-set! v (+ i 1) y)
        (vector-set! v (+ i 2) z)
        (set! i (+ i 3))))
    v))

(define (list<coord><-flat-vector<number> v)
  (for/list ((i (in-range 0 (vector-length v) 3)))
    (xyz
     (vector-ref v (+ i 0))
     (vector-ref v (+ i 1))
     (vector-ref v (+ i 2)))))

(define (list<coord><-flat-vector<number>-z v z)
  (for/list ((i (in-range 0 (vector-length v) 2)))
    (xyz
     (vector-ref v (+ i 0))
     (vector-ref v (+ i 1))
     z)))

(define (flat-vector<real><-bbox bbox)
  (flat-vector<real><-list<coord> (list<-bbox bbox)))